#include "TCPSock.h"

namespace poly
{

void TCPSock::initialize( SOCKET sock )
{
	s = sock;
}

TCPSock::TCPSock(void) : m_buffer(0), len(0)
{
	s = INVALID_SOCKET;
}


TCPSock::~TCPSock()
{
	delete [] m_buffer;
	m_buffer = 0;
	len = 0;
}

void TCPSock::create()
{
	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
}

int TCPSock::host(int port, int backlog)
{
	sockaddr_in adr;

	adr.sin_family		= AF_INET;
	adr.sin_port		= htons(port);
	adr.sin_addr.s_addr	= INADDR_ANY;
	ZeroMemory(adr.sin_zero,8);

	if( bind(s, (sockaddr*) &adr, sizeof(adr)) == SOCKET_ERROR )
		return SOCKET_ERROR;

	if( listen(s, backlog) == SOCKET_ERROR )
		return SOCKET_ERROR;

	return 0;
}

int TCPSock::client(char * adrstring, int port)
{
	sockaddr_in adr;

	adr.sin_family		= AF_INET;
	adr.sin_port		= htons(port);
	adr.sin_addr.s_addr	= inet_addr(adrstring);
	ZeroMemory(adr.sin_zero,8);

	return connect(s, (sockaddr*)&adr, sizeof(adr) );
}

int TCPSock::accept( TCPSock & acceptSock )
{
	SOCKET acceptS;
	acceptS = ::accept(s, 0, 0);
	if( acceptS != INVALID_SOCKET )
	{
		acceptSock.initialize( acceptS );
		return 0;
	}
	else
		return INVALID_SOCKET;
}

int TCPSock::setNonBlocking()
{
	unsigned long arg = 1;
	return ioctlsocket( s, FIONBIO, &arg );
}

int TCPSock::setBlocking()
{
	unsigned long arg = 0;
	return ioctlsocket( s, FIONBIO, &arg );
}

int TCPSock::send(char const *buffer, int len)
{
	return ::send( s, buffer, len, 0 );
}

int TCPSock::recv(int packSize)
{
	char * pack = new char[packSize];

	int recvSz;
	do
	{
		recvSz = ::recv(s, pack, packSize, 0);
		if( recvSz == SOCKET_ERROR )
		{
			delete [] pack;
			delete [] m_buffer;
			return SOCKET_ERROR;
		}
		else
		{
			char* newbuffer = new char[len+recvSz];
			memcpy(newbuffer,m_buffer,len);
			memcpy(newbuffer+len,pack,recvSz);
			delete [] m_buffer;
			m_buffer = newbuffer;
		}
	} while (recvSz == packSize);
	return len;
}

int TCPSock::poll()
{
	fd_set fdread;
	timeval timeout;
	timeout.tv_sec = 0;
	timeout.tv_usec = 0;

	FD_ZERO(&fdread);
	FD_SET(s,&fdread);
	return select(0, &fdread, 0, 0, &timeout);
}

void * TCPSock::buffer()
{
	return m_buffer;
}

int TCPSock::bufferSize()
{
	return len;
}

void TCPSock::clearBuffer()
{
	delete [] m_buffer;
	m_buffer = 0;
	len = 0;
}

int TCPSock::close()
{
	int out = closesocket(s);
	s = INVALID_SOCKET;
	return out;
}
} // end of poly
